﻿using System;
using System.Threading;

namespace mqtttLib.Helper.TcpSocket
{
    /// <summary>
    /// tcp 连接 没有重试 长连接优化
    /// </summary>
    public class TcpClient2
    {     /// <summary>
          /// 客户端 接受数据 事件
          /// </summary>
        public Action<byte[]> ReceiveEvent;
        /// <summary>
        /// 服务器地址
        /// </summary>
        private readonly string _ip;
        /// <summary>
        /// 端口
        /// </summary>
        private readonly int _port;

        /// <summary>
        /// 是否长连接
        /// </summary>
        private readonly bool _longConnection;
        /// <summary>
        /// 长连接接受标志
        /// </summary>
        private bool _longReceiveMark = true;
        /// <summary>
        /// 连接类
        /// </summary>
        private System.Net.Sockets.TcpClient _client;

        /// <summary>
        ///长连接 接受线程
        /// </summary>
        private Thread _threadReceive;
        /// <summary>
        /// 停止
        /// </summary>
        public void Stop()
        {
            _longReceiveMark = false;
            TryClose();
        }
        public TcpClient2(string ip, int port, int tryTimes, bool longConnection)
        {
            _ip = ip;
            _port = port;
            //  _tryTimes = tryTimes;
            _longConnection = longConnection;
            //_client.Available

        }
        public bool TryConnect()
        {
            try
            {
                _client = new System.Net.Sockets.TcpClient(_ip, _port);
                //长连接
                if (_longConnection)
                {
                    //创建线程 监听服务器 发来的消息
                    _threadReceive = new Thread(Accept)
                    {
                        IsBackground = true//设置为后台线程
                    };
                    //开启线程
                    _threadReceive.Start();
                }


                return true;
            }
            catch (Exception)
            {
                // ignored
            }

            return false;
        }

        private byte[] TryReceive()
        {
            try
            {
                byte[] buf = new byte[8192];
                //会产生阻塞
                var size = _client.Client.Receive(buf);
                //返回数据
                if (size > 0)
                {
                    byte[] data = new byte[size];
                    Array.Copy(buf, data, size);
                    return data;
                }
            }
            catch (Exception)
            {
                // ignored
            }

            return null;
        }

        private void Accept()
        {
            while (_longReceiveMark)
            {
                try
                {
                    //尝试连接中如果没有消息会产生阻塞
                    byte[] data = TryReceive();
                    if (data == null)
                    {
                        Thread.Sleep(100);
                    }
                    OnReceiveEvent(data);
                }
                catch (Exception ex)
                {
                    // ReSharper disable once PossibleIntendedRethrow
                    throw ex;
                }
            }
        }
        protected virtual void OnReceiveEvent(byte[] data)
        {
            ReceiveEvent?.Invoke(data);
        }

        private bool TrySend(byte[] data)
        {
            try
            {
                if (data != null)
                {

                    if (_client.Client.Send(data) > 0)
                        return true;
                }
            }
            catch (Exception)
            {
                // ignored
            }
            return false;
        }
        /// <summary>
        /// 关闭连接 长连接等于没操作
        /// </summary>
        private void TryClose()
        {
            if (!_longConnection)
            {
                _client.Client?.Close();
                _client?.Close();
                _client = null;
            }
        }


        /// <summary>
        /// 发送数据并接收数据
        /// </summary>
        /// <param name="sendData">待发送的数据</param>
        /// <returns></returns>
        public byte[] SendAndReceive(byte[] sendData)
        {
            if (_longConnection)
            {
                throw new Exception("长连接, 请用Send发送, 用ReceiveEvent接受");//长连接不能 使用
            }
            //链接
            if (!TryConnect())
                return null;
            byte[] result = null;
            //发送
            if (TrySend(sendData))
            {
                //接受数据
                result = TryReceive();
            }

            //关闭连接
            TryClose();
            return result;
        }
        public bool Send(byte[] sendData)
        {
            if (_client == null)
            {
                if (!TryConnect())
                    return false;
            }

            //发送数据
            bool result = TrySend(sendData);

            // 关闭连接 长连接等于没操作
            TryClose();

            if (!result)
            {
                //发送失败 关闭长连接线程
                if (_longConnection)
                {
                    if (_client != null)
                    {
                        _client.Client?.Close();
                        _client?.Close();
                    }
                    _client = null;
                    //关闭长连接线程
                    if (_threadReceive != null)
                    {
                        _longReceiveMark = false;
                        _threadReceive.Abort();//关闭
                        _longReceiveMark = true;
                    }

                }

            }
            return result;
        }

    }
}
